#include "GeometryLoader.h"
#include "GeometryGenerator.h"

#include <fstream>
using std::ifstream;

MeshDataPT	GeometryLoader<MeshDataPT>::m_Plane;
MeshDataPNT	GeometryLoader<MeshDataPNT>::m_Box;
MeshDataPNT	GeometryLoader<MeshDataPNT>::m_Sphere;

template<>
MeshDataPT* GeometryLoader<MeshDataPT>::GetPlane()
{
	if(!m_Plane.vertices.size())
	{
		GeometryGenerator::CreatePlanePT(1.0f, 1.0f, m_Plane);
	}

	return &m_Plane;
}

MeshDataPNT* GeometryLoader<MeshDataPNT>::GetBox()
{
	if(!m_Box.vertices.size())
	{
		GeometryGenerator::CreateBoxPNT(1.0f, 1.0f, 1.0f, m_Box);
	}

	return &m_Box;
}

MeshDataPNT* GeometryLoader<MeshDataPNT>::GetSphere()
{
	if(!m_Sphere.vertices.size())
	{
		GeometryGenerator::CreateGeospherePNT(1.0f, 32, m_Sphere);
	}

	return &m_Sphere;
}

bool GeometryLoader<AnimatedMeshDataPNT>::LoadAnimatedGeometry(string _filePath, AnimatedMeshDataPNT*& _mesh)
{
	map<string, AnimatedMeshDataPNT*>::iterator ite;

	ite = animatedMeshMap.find(_filePath);
	
	if(ite == animatedMeshMap.end())
	{
		AnimatedMeshDataPNT* mesh = new AnimatedMeshDataPNT();
		ifstream in;
		in.open(_filePath, std::ios_base::binary);

		size_t numVerts;

		in.read((char*) &numVerts, sizeof(size_t));

		mesh->vertices.resize(numVerts);
		mesh->weights.resize(numVerts);
		in.read((char*)&mesh->vertices[0], sizeof(mesh->vertices[0])*numVerts);

		size_t triCount;
		in.read((char*)&triCount, sizeof(size_t));

		mesh->indices.resize(triCount*3);
		in.read((char*)&mesh->indices[0], sizeof(mesh->indices[0])*triCount*3);

		for(size_t currVert = 0; currVert<numVerts; ++currVert)
		{
			size_t numWeights;

			in.read((char*)&numWeights, sizeof(size_t));

			mesh->weights[currVert].resize(numWeights);
			size_t size = sizeof(mesh->weights[currVert]);
			in.read((char*)&mesh->weights[currVert][0], sizeof(mesh->weights[currVert][0])*numWeights);
		}
	
		char boneName[256];
		size_t boneNameLength;
		size_t numBones;

		in.read((char*)&numBones, sizeof(size_t));

		mesh->joints.resize(numBones);

		for(size_t currBone = 0; currBone < numBones; ++currBone)
		{
			int parentInt;
		
			in.read((char*)&boneNameLength, sizeof(size_t));
			in.read(boneName,boneNameLength);
			in.read((char*)&parentInt,sizeof(parentInt));

			std::string jointName = boneName;
			mesh->joints[currBone].JointName = jointName;
			mesh->joints[currBone].transformFrame.SetBoneIndex(currBone);
			mesh->joints[currBone].transformFrame.SetBoneName(jointName);

			XMFLOAT4X4 localMat;
			in.read((char*)&mesh->joints[currBone].transformFrame.GetLocalMat(), sizeof(XMFLOAT4X4));
		}
	
		for(size_t currBone = 0; currBone < numBones; ++currBone)
		{
			size_t numChildren;

			in.read((char*)&numChildren, sizeof(size_t));
			for(size_t currChild = 0; currChild < numChildren; ++currChild)
			{
				size_t childIndex;
				in.read((char*)&childIndex, sizeof(unsigned int));
				mesh->joints[currBone].transformFrame.AddChild(&mesh->joints[childIndex].transformFrame);
			}
		}

		_mesh = mesh;

		_mesh->joints[0].transformFrame.Update();

		animatedMeshMap.insert(map<string, AnimatedMeshDataPNT*>::value_type(_filePath, mesh));

		in.close();
		return true;
	}
	else
	{
		_mesh = (ite->second);
		return true;
	}

	return false;
}